package com.code.gen.util;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.code.gen.bean.bo.CodeGenProperties;
import com.code.gen.bean.bo.CodeGenPropertiesSystem;
import com.code.gen.bean.bo.database.CodeGenField;
import com.code.gen.bean.bo.database.CodeGenTable;
import com.code.gen.bean.bo.file.CodeGenFieldProperties;
import com.code.gen.bean.bo.file.CodeGenFileProperties;
import com.code.gen.constant.CodeGenConstant;
import com.code.gen.enums.ECodeGenFieldEquals;
import com.code.gen.enums.ECodeGenPlaceholder;
import com.sojson.util.StringUtil;

/**
 * 初始化动态数据类
 *
 * @author liu
 * @date 2020-08-20
 */
public class CodeGenPropertiesUtil {

    private CodeGenProperties properties;
    private CodeGenPropertiesSystem system;

    public CodeGenPropertiesUtil(CodeGenProperties properties) {
        this.properties = properties;
        this.system = properties.getSystem();
    }

    /**
     * 初始化属性
     */
    public void initProperties() {
        List<CodeGenFileProperties> files = properties.getFiles();

        List<CodeGenTable> tables = properties.getDatabase().getTables();
        for (CodeGenTable table : tables) {
            files.add(initProperties(table));
        }
    }

    /**
     * 初始化属性
     *
     * @param table
     * @return
     */
    public CodeGenFileProperties initProperties(CodeGenTable table) {
        CodeGenFileProperties file = new CodeGenFileProperties();

        // 初始化属性
        file.setClassNameD(table.getClassName());
        file.setClassNameX(toLowerCase(file.getClassNameD()));
        file.setParamNameD(getClassNameD(table.getClassName()));
        file.setParamNameX(toLowerCase(file.getParamNameD()));
        file.setBeanName(getBeanName(file.getClassNameD()));

        file.setClassComment(table.getTableComment() != null ? table.getTableComment() : "");
        file.setSerialVersionUid(System.currentTimeMillis() + "L");
        file.setClassCommentDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        file.setExistId(table.getExistId());
        if (file.getExistId()) {
            file.setDatabaseIdName(table.getIdName());
            if (null != file.getDatabaseIdName()) {
                file.setDatabaseIdNameD(file.getDatabaseIdName().toUpperCase());
                file.setJavaIdNameD(toUpperCase(enableFieldMapUnderscoreToCamelCase(table.getIdName())));
                file.setJavaIdNameX(toLowerCase(file.getJavaIdNameD()));
                if (StringUtil.isBlank(file.getXing())) {
                    file.setXing(file.getDatabaseIdName());
                    file.setXingD(file.getDatabaseIdNameD());
                }
            }
        }
        file.setExistSerialNumber(table.getExistSerialNumber());
        if (file.getExistSerialNumber()) {
            file.setDatabaseSerialNumberName(table.getSerialNumberName());
            if (null != file.getDatabaseSerialNumberName()) {
                file.setDatabaseSerialNumberNameD(file.getDatabaseSerialNumberName().toUpperCase());
                file.setJavaSerialNumberNameD(
                    toUpperCase(enableFieldMapUnderscoreToCamelCase(table.getSerialNumberName())));
                file.setJavaSerialNumberNameX(toLowerCase(file.getJavaSerialNumberNameD()));
            }
        }
        file.setExistDel(table.getExistDel());
        if (file.getExistDel()) {
            file.setDatabaseDelName(table.getDelName());
            if (null != file.getDatabaseDelName()) {
                file.setDatabaseDelNameD(file.getDatabaseDelName().toUpperCase());
                file.setJavaDelNameD(toUpperCase(enableFieldMapUnderscoreToCamelCase(table.getDelName())));
                file.setJavaDelNameX(toLowerCase(file.getJavaDelNameD()));
            }
        }
        if (StringUtil.isBlank(file.getXing())) {
            file.setXing(1 + "");
            file.setXingD(file.getDatabaseDelNameD());
        }
        int[] delNumberList = system.getDelNumberList();
        if (delNumberList != null && delNumberList.length > 0) {
            int twoLen = 2;
            int length = delNumberList.length;
            StringBuilder stringBuilder = new StringBuilder();
            if (length == twoLen) {
                int number = system.getDelNumber();
                int one = delNumberList[0];
                int two = delNumberList[1];
                if (one != number) {
                    number = one;
                    stringBuilder.append("= ").append(number);
                } else if (two != number) {
                    number = two;
                    stringBuilder.append("= ").append(number);
                } else {
                    stringBuilder.append("!= ").append(number);
                }
            } else {
                stringBuilder.append("IN (");
                for (int i : delNumberList) {
                    if (i != system.getDelNumber()) {
                        stringBuilder.append(i).append(",");
                    }
                }
                String k = "(";
                if (stringBuilder.indexOf(k) == stringBuilder.length() - 1) {
                    stringBuilder = new StringBuilder("!= ").append(system.getDelNumber());
                } else {
                    String substring = stringBuilder.substring(0, stringBuilder.length() - 1);
                    stringBuilder = new StringBuilder(substring + ")");
                }
            }
            file.setDelNumberList(stringBuilder.toString());
        } else {
            // 给个空字符串防止空指针
            file.setDelNumberList("");
        }
        file.setTableName(table.getTableName());

        // 初始化基础路径
        String basePath = table.getPackageName();
        if (basePath != null) {
            basePath = CodeGenReadTemplate.removeD(basePath.replace(" ", "").replace("\\", ".").replace("/", "."));
            if (basePath.length() == 0) {
                basePath = "";
            }
        } else {
            basePath = "";
        }
        file.setPackageName(basePath);
        String moduleName = table.getModuleName();
        if (moduleName != null) {
            moduleName = CodeGenReadTemplate.removeD(moduleName.replace(" ", "").replace("\\", ".").replace("/", "."));
            if (moduleName.length() == 0) {
                moduleName = "";
            }
        } else {
            moduleName = "";
        }
        String businessName = table.getBusinessName();
        if (businessName != null) {
            businessName =
                CodeGenReadTemplate.removeD(businessName.replace(" ", "").replace("\\", ".").replace("/", "."));
            if (businessName.length() == 0) {
                businessName = "";
            }
        } else {
            businessName = "";
        }
        if (StringUtil.isBlank(moduleName)) {
            moduleName = businessName;
        } else {
            moduleName = moduleName + "." + businessName;
        }
        file.setTableNameD(file.getTableName().toUpperCase());
        file.setCreateSql(table.getCreateSql());
        file.setPackageName(table.getPackageName());
        file.setModuleName(moduleName);
        file.setBusinessName(table.getBusinessName());
        file.setFunctionName(table.getFunctionName());
        file.setFunctionAuthor(table.getFunctionAuthor());
        file.setGenType(table.getGenType());
        file.setGenPath(table.getGenPath());
        file.setOptions(table.getOptions());
        file.setParentMenuId(table.getParentMenuId());
        file.setParentMenuName(table.getParentMenuName());

        for (CodeGenField field : table.getFields()) {
            initFieldAndMethod(field, file, table);
        }

        return file;
    }

    /**
     * 初始化属性
     */
    public void initProperties(CodeGenFileProperties file) {
        Map<String, String> placeholders = properties.getPlaceholders();

        // 初始化属性
        // 类信息
        placeholders.put(ECodeGenPlaceholder.CLASS_COMMENT.getPlaceholder(), file.getClassComment());
        placeholders.put(ECodeGenPlaceholder.CLASS_AUTHOR.getPlaceholder(), file.getFunctionAuthor());
        placeholders.put(ECodeGenPlaceholder.DATE.getPlaceholder(), file.getClassCommentDate());
        placeholders.put(ECodeGenPlaceholder.SERIAL_VERSION_UIN.getPlaceholder(), file.getSerialVersionUid());
        placeholders.put(ECodeGenPlaceholder.CLASS_NAME_X.getPlaceholder(), file.getClassNameX());
        placeholders.put(ECodeGenPlaceholder.CLASS_NAME_D.getPlaceholder(), file.getClassNameD());
        placeholders.put(ECodeGenPlaceholder.CLASS_PARAM_NAME_X.getPlaceholder(), file.getParamNameX());
        placeholders.put(ECodeGenPlaceholder.CLASS_PARAM_NAME_D.getPlaceholder(), file.getParamNameD());
        placeholders.put(ECodeGenPlaceholder.CLASS_PARAM_NAME_X.getPlaceholder(), file.getParamNameX());
        placeholders.put(ECodeGenPlaceholder.CLASS_PARAM_NAME_D.getPlaceholder(), file.getParamNameD());
        placeholders.put(ECodeGenPlaceholder.CLASS_BEAN_NAME.getPlaceholder(), file.getBeanName());
        placeholders.put(ECodeGenPlaceholder.CONTROLLER_URL.getPlaceholder(),
            "/" + file.getModuleName().replace(".", "/"));
        if (system.isControllerMappingSuffix()) {
            placeholders.put(ECodeGenPlaceholder.CONTROLLER_SUFFIX_ACTION.getPlaceholder(), CodeGenConstant.D_ACTION);
            placeholders.put(ECodeGenPlaceholder.CONTROLLER_SUFFIX_SHOW.getPlaceholder(), CodeGenConstant.D_SHOW_);
            placeholders.put(ECodeGenPlaceholder.CONTROLLER_SUFFIX_DO.getPlaceholder(), CodeGenConstant.D_DO_);
        } else {
            placeholders.put(ECodeGenPlaceholder.CONTROLLER_SUFFIX_ACTION.getPlaceholder(), "");
            placeholders.put(ECodeGenPlaceholder.CONTROLLER_SUFFIX_SHOW.getPlaceholder(), "");
            placeholders.put(ECodeGenPlaceholder.CONTROLLER_SUFFIX_DO.getPlaceholder(), "");
        }

        // 数据库信息
        placeholders.put(ECodeGenPlaceholder.DB_NAME.getPlaceholder(), properties.getDatabase().getDatabaseName());
        placeholders.put(ECodeGenPlaceholder.TABLE_NAME.getPlaceholder(), file.getTableName());
        placeholders.put(ECodeGenPlaceholder.TABLE_NAME_D.getPlaceholder(), file.getTableNameD());
        placeholders.put(ECodeGenPlaceholder.CREATE_SQL.getPlaceholder(), file.getCreateSql());

        // *
        placeholders.put(ECodeGenPlaceholder.XING.getPlaceholder(), file.getXingD());

        // 特殊字段
        if (file.getExistId()) {
            placeholders.put(ECodeGenPlaceholder.ID_JDBC_TYPE.getPlaceholder(), file.getXmlIdType());
            placeholders.put(ECodeGenPlaceholder.ID_COMMENT.getPlaceholder(), file.getJavaIdComment());
            placeholders.put(ECodeGenPlaceholder.ID_D.getPlaceholder(), file.getJavaIdNameD());
            placeholders.put(ECodeGenPlaceholder.ID_X.getPlaceholder(), file.getJavaIdNameX());
            placeholders.put(ECodeGenPlaceholder.ID_DATABASE_FIELD_Y.getPlaceholder(), file.getDatabaseIdName());
            placeholders.put(ECodeGenPlaceholder.ID_DATABASE_FIELD_D.getPlaceholder(), file.getDatabaseIdNameD());
            placeholders.put(ECodeGenPlaceholder.ID_XML_PARAM_TYPE.getPlaceholder(), file.getXmlIdParamType());
            placeholders.put(ECodeGenPlaceholder.ID_JAVA_TYPE.getPlaceholder(), file.getJavaIdType());
        }
        if (file.getExistSerialNumber()) {
            placeholders.put(ECodeGenPlaceholder.SERIAL_NUMBER_JDBC_TYPE.getPlaceholder(),
                file.getXmlSerialNumberType());
            placeholders.put(ECodeGenPlaceholder.SERIAL_NUMBER_COMMENT.getPlaceholder(), file.getJavaIdComment());
            placeholders.put(ECodeGenPlaceholder.SERIAL_NUMBER_D.getPlaceholder(), file.getJavaSerialNumberNameD());
            placeholders.put(ECodeGenPlaceholder.SERIAL_NUMBER_X.getPlaceholder(), file.getJavaSerialNumberNameX());
            placeholders.put(ECodeGenPlaceholder.SERIAL_NUMBER_DATABASE_FIELD_Y.getPlaceholder(),
                file.getDatabaseSerialNumberName());
            placeholders.put(ECodeGenPlaceholder.SERIAL_NUMBER_DATABASE_FIELD_D.getPlaceholder(),
                file.getDatabaseSerialNumberNameD());
            placeholders.put(ECodeGenPlaceholder.SERIAL_NUMBER_XML_PARAM_TYPE.getPlaceholder(),
                file.getXmlSerialNumberParamType());
            placeholders.put(ECodeGenPlaceholder.SERIAL_NUMBER_JAVA_TYPE.getPlaceholder(),
                file.getJavaSerialNumberType());
        }
        if (file.getExistDel()) {
            placeholders.put(ECodeGenPlaceholder.DEL_JDBC_TYPE.getPlaceholder(), file.getXmlDelType());
            placeholders.put(ECodeGenPlaceholder.DEL_COMMENT.getPlaceholder(), file.getJavaIdComment());
            placeholders.put(ECodeGenPlaceholder.DEL_D.getPlaceholder(), file.getJavaDelNameD());
            placeholders.put(ECodeGenPlaceholder.DEL_X.getPlaceholder(), file.getJavaDelNameX());
            placeholders.put(ECodeGenPlaceholder.DEL_DATABASE_Y.getPlaceholder(), file.getDatabaseDelName());
            placeholders.put(ECodeGenPlaceholder.DEL_DATABASE_D.getPlaceholder(), file.getDatabaseDelNameD());
            placeholders.put(ECodeGenPlaceholder.DEL_XML_PARAM_TYPE.getPlaceholder(), file.getXmlDelParamType());
            placeholders.put(ECodeGenPlaceholder.DEL_JAVA_TYPE.getPlaceholder(), file.getJavaDelType());
            placeholders.put(ECodeGenPlaceholder.DEL_DATABASE_NUMBER.getPlaceholder(), system.getDelNumber() + "");
            placeholders.put(ECodeGenPlaceholder.DEL_DATABASE_NUMBER_NOT.getPlaceholder(),
                system.getDelNumberNot() + "");
        }
        placeholders.put(ECodeGenPlaceholder.CREATE_TIME_DATABASE_FIELD_D.getPlaceholder(),
            file.getDatabaseCreateTimeNameD());
    }

    /**
     * 初始化字段和方法
     *
     * @param field
     * @param table
     * @param fileProperties
     * @param table
     */
    private void initFieldAndMethod(CodeGenField field, CodeGenFileProperties fileProperties, CodeGenTable table) {
        List<CodeGenFieldProperties> fileFeilds = fileProperties.getFileFeild();
        CodeGenFieldProperties fileFeild = new CodeGenFieldProperties();
        fileFeilds.add(fileFeild);

        // 初始化字段
        fileFeild.setFieldEquals(field.getFieldEquals());
        fileFeild.setFieldComment(field.getColumnComment());
        String javaField = field.getJavaField();
        if (StringUtil.isNotBlankString(javaField)) {
            fileFeild.setFieldNameD(toUpperCase(javaField));
            fileFeild.setFieldNameX(toLowerCase(fileFeild.getFieldNameD()));
        } else {
            fileFeild
                .setFieldNameD(toUpperCase(enableFieldMapUnderscoreToCamelCase(field.getColumnName().toLowerCase())));
            fileFeild.setFieldNameX(toLowerCase(fileFeild.getFieldNameD()));
        }
        fileFeild.setFieldNameDatabase(field.getColumnName());
        fileFeild.setFieldNameDatabaseD(fileFeild.getFieldNameDatabase().toUpperCase());
        if (StringUtil.isBlank(fileProperties.getXing())) {
            fileProperties.setXing(fileFeild.getFieldNameDatabase());
            fileProperties.setXingD(fileFeild.getFieldNameDatabaseD());
        }

        // 遍历查询字段对应的类型
        for (ECodeGenFieldEquals fieldEquals : ECodeGenFieldEquals.values()) {
            if (null != fieldEquals.getDatabase()) {
                if (fieldEquals.getDatabase().equalsIgnoreCase(field.getColumnType())) {
                    fileFeild.setFieldDatabaseType(fieldEquals.getDatabase());
                    fileFeild.setFieldXmlType(fieldEquals.getXml());
                    fileFeild.setFieldJavaType(fieldEquals.getJava());
                    fileFeild.setFieldXmlParamType(fieldEquals.getXmlParam());
                    break;
                }
            }
        }
        String javaType = field.getJavaType();
        if (StringUtil.isNotBlankString(javaType)) {
            for (ECodeGenFieldEquals fieldEquals : ECodeGenFieldEquals.values()) {
                if (null != fieldEquals.getJava()) {
                    if (fieldEquals.getJava().equalsIgnoreCase(javaType)) {
                        fileFeild.setFieldJavaType(fieldEquals.getJava());
                        fileFeild.setFieldXmlParamType(fieldEquals.getXmlParam());
                        break;
                    }
                }
            }
        }
        if (fileProperties.getExistId() && fileProperties.getXmlIdType() == null) {
            if (fileProperties.getDatabaseIdName().equals(field.getColumnName())) {
                fileProperties.setXmlIdType(fileFeild.getFieldXmlType());
                fileProperties.setXmlIdParamType(fileFeild.getFieldXmlParamType());
                fileProperties.setJavaIdComment(fileFeild.getFieldComment());
                fileProperties.setJavaIdType(fileFeild.getFieldJavaType());
            }
        }
        if (fileProperties.getExistSerialNumber() && fileProperties.getXmlSerialNumberType() == null) {
            if (fileProperties.getDatabaseSerialNumberName().equals(field.getColumnName())) {
                fileProperties.setXmlSerialNumberType(fileFeild.getFieldXmlType());
                fileProperties.setXmlSerialNumberParamType(fileFeild.getFieldXmlParamType());
                fileProperties.setJavaSerialNumberComment(fileFeild.getFieldComment());
                fileProperties.setJavaSerialNumberType(fileFeild.getFieldJavaType());
            }
        }
        if (fileProperties.getExistDel() && fileProperties.getXmlDelType() == null) {
            if (fileProperties.getDatabaseDelName().equals(field.getColumnName())) {
                fileProperties.setXmlDelType(fileFeild.getFieldXmlType());
                fileProperties.setXmlDelParamType(fileFeild.getFieldXmlParamType());
                fileProperties.setJavaDelComment(fileFeild.getFieldComment());
                fileProperties.setJavaDelType(fileFeild.getFieldJavaType());
            }
        }
        if (system.getCreateTime().equals(fileFeild.getFieldNameX())) {
            fileProperties.setDatabaseCreateTimeNameD(fileFeild.getFieldNameDatabaseD());
        }
        fileFeild.setIsPk(field.getIsPk());
        fileFeild.setIsIncrement(field.getIsIncrement());
        fileFeild.setIsRequired(field.getIsRequired());
        fileFeild.setIsAdd(field.getIsAdd());
        fileFeild.setIsEdit(field.getIsEdit());
        fileFeild.setIsList(field.getIsList());
        fileFeild.setIsQuery(field.getIsQuery());
        fileFeild.setQueryType(field.getQueryType());
        fileFeild.setHtmlType(field.getHtmlType());
        fileFeild.setDictType(field.getDictType());
    }

    /**
     * 初始化包名
     *
     * @return
     */
    public String initPackageName(String path) {
        String one = ":/";
        int indexOf = path.indexOf(one);
        if (indexOf != -1) {
            path = path.substring(indexOf + one.length());
        }
        return path.replace("/", ".");
    }

    /**
     * 字段名驼峰命名转换
     *
     * @return
     */
    public static String enableFieldMapUnderscoreToCamelCase(String name) {
        StringBuilder stringBuilder = new StringBuilder();
        if (CodeGenPropertiesSystem.enableFieldMapUnderscoreToCamelCase) {
            String[] split = name.split(StringUtil.SEPARATOR);
            stringBuilder.append(split[0]);
            for (int i = 1; i < split.length; i++) {
                String string = split[i];
                if (string.length() > 0) {
                    stringBuilder.append(toUpperCase(split[i]));
                } else {
                    continue;
                }
            }
        } else {
            stringBuilder.append(name);
        }
        return stringBuilder.toString();
    }

    /**
     * 将单词首字母转为大写
     *
     * @return
     */
    public static String toUpperCase(String name) {
        StringBuilder stringBuilder = new StringBuilder();
        if (name.length() > 0) {
            stringBuilder.append(name.substring(0, 1).toUpperCase());
            if (name.length() > 1) {
                stringBuilder.append(name.substring(1, name.length()));
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 将单词首字母转为小写
     *
     * @return
     */
    public static String toLowerCase(String name) {
        StringBuilder stringBuilder = new StringBuilder();
        if (name.length() > 0) {
            stringBuilder.append(name.substring(0, 1).toLowerCase());
            if (name.length() > 1) {
                stringBuilder.append(name.substring(1, name.length()));
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 类名驼峰命名转换
     *
     * @return
     */
    public String enableClassMapUnderscoreToCamelCase(String name) {
        StringBuilder stringBuilder = new StringBuilder();
        if (CodeGenPropertiesSystem.enableClassMapUnderscoreToCamelCase) {
            String[] split = name.split(StringUtil.SEPARATOR);
            stringBuilder.append(split[0]);
            for (int i = 1; i < split.length; i++) {
                String string = split[i];
                if (string.length() > 0) {
                    stringBuilder.append(toUpperCase(split[i]));
                } else {
                    continue;
                }
            }
        } else {
            stringBuilder.append(name);
        }
        return stringBuilder.toString();
    }

    /**
     * 获取类名
     *
     * @param name
     * @return
     */
    public String getClassNameD(String name) {
        return toUpperCase(enableClassMapUnderscoreToCamelCase(toLowerCase(name)));
    }

    /**
     * 获取Bean对象名(如果以两个或以上的大写字母开头就是原类名,否则是首字母小写)
     *
     * @param tableName
     * @return
     */
    private String getBeanName(String name) {
        char one = name.charAt(0);
        char two = name.charAt(1);
        char a = 'A';
        char z = 'Z';
        if (a <= one && one <= z && a <= two && two <= z) {
            return name;
        }
        return toLowerCase(name);
    }

}